home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / hamradio / tnos-2.000 / tnos-2 / icmp.c < prev    next >
C/C++ Source or Header  |  1996-06-23  |  7KB  |  287 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "iface.h"
  7. #include "icmp.h"
  8.  
  9. #if !defined(_lint) && !defined(MSDOS)
  10. static char rcsid[] OPTIONAL = "$Id: icmp.c,v 1.8 1996/06/24 02:54:26 root Exp root $";
  11. #endif
  12.  
  13. struct mib_entry DFAR Icmp_mib[] =
  14. {
  15.     { "",                {0}},
  16.     { "icmpInMsgs",            {0}},
  17.     { "icmpInErrors",        {0}},
  18.     { "icmpInDestUnreachs",     {0}},
  19.     { "icmpInTimeExcds",        {0}},
  20.     { "icmpInParmProbs",        {0}},
  21.     { "icmpInSrcQuenchs",        {0}},
  22.     { "icmpInRedirects",        {0}},
  23.     { "icmpInEchos",        {0}},
  24.     { "icmpInEchoReps",        {0}},
  25.     { "icmpInTimestamps",        {0}},
  26.     { "icmpInTimestampReps",    {0}},
  27.     { "icmpInAddrMasks",        {0}},
  28.     { "icmpInAddrMaskReps",        {0}},
  29.     { "icmpOutMsgs",        {0}},
  30.     { "icmpOutErrors",        {0}},
  31.     { "icmpOutDestUnreachs",    {0}},
  32.     { "icmpOutTimeExcds",        {0}},
  33.     { "icmpOutParmProbs",        {0}},
  34.     { "icmpOutSrcQuenchs",        {0}},
  35.     { "icmpOutRedirects",        {0}},
  36.     { "icmpOutEchos",        {0}},
  37.     { "icmpOutEchoReps",        {0}},
  38.     { "icmpOutTimestamps",        {0}},
  39.     { "icmpOutTimestampReps",    {0}},
  40.     { "icmpOutAddrMasks",        {0}},
  41.     { "icmpOutAddrMaskReps",    {0}},
  42. };
  43.  
  44.  
  45. /* Process an incoming ICMP packet */
  46. void
  47. icmp_input (iface, ip, bp, rxbroadcast)
  48. struct iface *iface OPTIONAL;    /* Incoming interface (ignored) */
  49. struct ip *ip;            /* Pointer to decoded IP header structure */
  50. struct mbuf *bp;        /* Pointer to ICMP message */
  51. int rxbroadcast;
  52. {
  53. struct icmplink *ipp;
  54. struct mbuf *tbp;
  55. struct icmp icmp;    /* ICMP header */
  56. struct ip oip;        /* Offending datagram header */
  57. int16 type;        /* Type of ICMP message */
  58. int16 length;
  59. int ok_trace;
  60. char temp[40];
  61.  
  62.     icmpInMsgs++;
  63.     if (rxbroadcast) {
  64.         /* Broadcast ICMP packets are to be IGNORED !! */
  65.         icmpInErrors++;
  66.         free_p (bp);
  67.         return;
  68.     }
  69.     length = ip->length - IPLEN - ip->optlen;
  70.     if (cksum (NULLHEADER, bp, length) != 0) {
  71.         /* Bad ICMP checksum; discard */
  72.         icmpInErrors++;
  73.         free_p (bp);
  74.         return;
  75.     }
  76.     (void) ntohicmp (&icmp, &bp);
  77.  
  78.     /* Process the message. Some messages are passed up to the protocol
  79.      * module for handling, others are handled here.
  80.      */
  81.     type = (int16) icmp.type;        /*lint !e571 */
  82.  
  83.     switch (uchar (type)) {
  84.         case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  85.         case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  86.         case ICMP_QUENCH:    /* Source Quench */
  87.             switch (uchar (type)) {
  88.                 case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  89.                     icmpInTimeExcds++;
  90.                     break;
  91.                 case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  92.                     icmpInDestUnreachs++;
  93.                     break;
  94.                 case ICMP_QUENCH:    /* Source Quench */
  95.                     icmpInSrcQuenchs++;
  96.                     break;
  97.                 default:
  98.                     break;
  99.             }
  100.             (void) ntohip (&oip, &bp);    /* Extract offending IP header */
  101.             if (Icmp_trace) {
  102.                 switch (uchar (type)) {
  103.                     case ICMP_TIME_EXCEED:
  104.                         ok_trace = 1;
  105.                         sprintf (temp, "%s",
  106.                              smsg (Exceed, NEXCEED, (unsigned) uchar (icmp.code)));
  107.                         break;
  108.                     case ICMP_DEST_UNREACH:
  109.                         ok_trace = 1;
  110.                         sprintf (temp, "%s",
  111.                              smsg (Unreach, NUNREACH, (unsigned) uchar (icmp.code)));
  112.                         break;
  113.                     default:
  114.                         ok_trace = 0;
  115.                         sprintf (temp, "%u", uchar (icmp.code));
  116.                         break;
  117.                 }
  118.  
  119.                 if ((Icmp_trace == 1) || (Icmp_trace == 2 && ok_trace)) {
  120.  
  121.                     tcmdprintf ("ICMP from %s:", inet_ntoa (ip->source));
  122.                     tcmdprintf (" dest %s %s ", inet_ntoa (oip.dest),
  123.                             smsg (Icmptypes, ICMP_TYPES, (unsigned) uchar (type)));
  124.                     tcmdprintf (" %s\n", temp);
  125.  
  126.                 }
  127.             }
  128.             for (ipp = Icmplink; ipp->funct != NULL; ipp++)
  129.                 if (ipp->proto == oip.protocol)
  130.                     break;
  131.             if (ipp->funct != NULL) {
  132.                 (*ipp->funct) (ip->source, oip.source, oip.dest, icmp.type, icmp.code, &bp);
  133.             }
  134.             break;
  135.         case ICMP_ECHO:/* Echo Request */
  136.             /* Change type to ECHO_REPLY, recompute checksum,
  137.              * and return datagram.
  138.              */
  139.             icmpInEchos++;
  140.             icmp.type = ICMP_ECHO_REPLY;
  141.             if ((tbp = htonicmp (&icmp, bp)) == NULLBUF) {
  142.                 free_p (bp);
  143.                 return;
  144.             }
  145.             icmpOutEchoReps++;
  146.             (void) ip_send (ip->dest, ip->source, ICMP_PTCL, ip->tos, 0, tbp, length, 0, 0);
  147.             return;
  148.         case ICMP_REDIRECT:    /* Redirect */
  149.             icmpInRedirects++;
  150.             break;
  151.         case ICMP_PARAM_PROB:    /* Parameter Problem */
  152.             icmpInParmProbs++;
  153.             break;
  154.         case ICMP_ECHO_REPLY:    /* Echo Reply */
  155.             icmpInEchoReps++;
  156.             echo_proc (ip->source, ip->dest, &icmp, bp);
  157.             bp = NULLBUF;    /* so it won't get freed */
  158.             break;
  159.         case ICMP_TIMESTAMP:    /* Timestamp */
  160.             icmpInTimestamps++;
  161.             break;
  162.         case ICMP_TIME_REPLY:    /* Timestamp Reply */
  163.             icmpInTimestampReps++;
  164.             break;
  165.         case ICMP_INFO_RQST:    /* Information Request */
  166.             break;
  167.         case ICMP_INFO_REPLY:    /* Information Reply */
  168.         default:
  169.             break;
  170.     }
  171.     free_p (bp);
  172. }
  173.  
  174.  
  175. /*lint -esym(18,icmp_output) */
  176. /* Return an ICMP response to the sender of a datagram.
  177.  * Unlike most routines, the callER frees the mbuf.
  178.  */
  179. int
  180. icmp_output (ip, data, type, code, args)
  181. struct ip *ip;            /* Header of offending datagram */
  182. struct mbuf *data;        /* Data portion of datagram */
  183. char type, code;        /* Codes to send */
  184. union icmp_args *args;
  185. {
  186. struct mbuf *bp = NULLBUF;
  187. struct icmp icmp;    /* ICMP protocol header */
  188. int16 dlen;        /* Length of data portion of offending pkt */
  189. int16 length;        /* Total length of reply */
  190.  
  191.     if (ip == NULLIP)
  192.         return -1;
  193.     if (uchar (ip->protocol) == ICMP_PTCL) {
  194.         /* Peek at type field of ICMP header to see if it's safe to
  195.          * return an ICMP message
  196.          */
  197.         switch (uchar (data->data[0])) {
  198.             case ICMP_ECHO_REPLY:
  199.             case ICMP_ECHO:
  200.             case ICMP_TIMESTAMP:
  201.             case ICMP_TIME_REPLY:
  202.             case ICMP_INFO_RQST:
  203.             case ICMP_INFO_REPLY:
  204.                 break;    /* These are all safe */
  205.             default:
  206.                 /* Never send an ICMP error message about another
  207.                  * ICMP error message!
  208.                  */
  209.                 return -1;
  210.         }
  211.     }
  212.     /* Compute amount of original datagram to return.
  213.      * We return the original IP header, and up to 8 bytes past that.
  214.      */
  215.     dlen = len_p (data);
  216.     dlen = min (8, dlen);
  217.     length = (int16) (dlen + ICMPLEN + IPLEN + ip->optlen);
  218.     /* Take excerpt from data portion */
  219.     if (data != NULLBUF && dup_p (&bp, data, 0, dlen) == 0)
  220.         return -1;    /* The caller will free data */
  221.  
  222.     /* Recreate and tack on offending IP header */
  223.     if ((data = htonip (ip, bp, IP_CS_NEW)) == NULLBUF) {
  224.         free_p (bp);
  225.         icmpOutErrors++;
  226.         return -1;
  227.     }
  228.     icmp.type = type;
  229.     icmp.code = code;
  230.     icmp.args.unused = 0;
  231.     switch (uchar (icmp.type)) {
  232.         case ICMP_PARAM_PROB:
  233.             icmpOutParmProbs++;
  234.             icmp.args.pointer = args->pointer;
  235.             break;
  236.         case ICMP_REDIRECT:
  237.             icmpOutRedirects++;
  238.             icmp.args.address = args->address;
  239.             break;
  240.         case ICMP_ECHO:
  241.             icmpOutEchos++;
  242.             break;
  243.         case ICMP_ECHO_REPLY:
  244.             icmpOutEchoReps++;
  245.             break;
  246.         case ICMP_INFO_RQST:
  247.             break;
  248.         case ICMP_INFO_REPLY:
  249.             break;
  250.         case ICMP_TIMESTAMP:
  251.             icmpOutTimestamps++;
  252.             break;
  253.         case ICMP_TIME_REPLY:
  254.             icmpOutTimestampReps++;
  255.             icmp.args.echo.id = args->echo.id;
  256.             icmp.args.echo.seq = args->echo.seq;
  257.             break;
  258.         case ICMP_ADDR_MASK:
  259.             icmpOutAddrMasks++;
  260.             break;
  261.         case ICMP_ADDR_MASK_REPLY:
  262.             icmpOutAddrMaskReps++;
  263.             break;
  264.         case ICMP_DEST_UNREACH:
  265.             if (icmp.code == ICMP_FRAG_NEEDED)
  266.                 icmp.args.mtu = args->mtu;
  267.             icmpOutDestUnreachs++;
  268.             break;
  269.         case ICMP_TIME_EXCEED:
  270.             icmpOutTimeExcds++;
  271.             break;
  272.         case ICMP_QUENCH:
  273.             icmpOutSrcQuenchs++;
  274.             break;
  275.         default:
  276.             break;
  277.     }
  278.  
  279.     icmpOutMsgs++;
  280.     /* Now stick on the ICMP header */
  281.     if ((bp = htonicmp (&icmp, data)) == NULLBUF) {
  282.         free_p (data);
  283.         return -1;
  284.     }
  285.     return ip_send (INADDR_ANY, ip->source, ICMP_PTCL, ip->tos, 0, bp, length, 0, 0);
  286. }
  287.